package ru.niir.goodfil.ui;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import ru.niir.goodfil.audit.util.BooleanReference;
import ru.niir.goodfil.db.GoodfilFactory;
import ru.niir.goodfil.db.handlers.Goodfil;
import ru.niir.goodfil.ui.tasks.*;
import ru.niir.goodfil.ui.utils.RestsExportManager;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
 * @author Сазонов
 */
public class ApplicationInit implements ServletContextListener {
    private static final Logger logger = Logger.getLogger(ApplicationInit.class);

    private final List<Timer> timers = new ArrayList<Timer>();

    private static final boolean SERVICE_SEND_TEST_RESTS = true;

    private static final boolean SERVICE_RESTS_VALIDATION = false;

    private static final boolean SERVICE_PERSONAL_PRICES_EXPIRATION = false;

    private static final boolean SERVICE_ENVIROMENT_VALIDATION = true;

    private static final String SEND_RESTS_TEST = ".send.rests.test";

    private static final int SEND_RESTS_TEST_DEFAULT = 1;

    private static final String SEND_RESTS_TEST_COMMENT = "Отправлять тестовые остатки";

    private static final String SEND_RESTS_TEST_EMAIL = ".send.rests.test.client";

    private static final int SEND_RESTS_TEST_EMAIL_VALUE = 1410;

    private static final String SEND_RESTS_TEST_EMAIL_COMMENT = "Адрес, на который высылаются тестовые остатки";

    private static final String RESTS_VALIDATION_TIMEOUT_KEY = "rests.validation.timeout";

    private static final int RESTS_VALIDATION_TIMEOUT_DEFAULT = 60 * 60;

    private static final String PERSONAL_PRICE_EXPIRATION_TIMEOUT_KEY = "personal.price.expiration.timeout";

    private static final int PERSONAL_PRICE_EXPIRATION_TIMEOUT_DEFAULT = 10;

    private static final String ENVIROMENT_VALIDATION_TIMEOUT_KEY = "every.hour.timeout";

    private static final int ENVIROMENT_VALIDATION_TIMEOUT_DEFAULT = 60 * 60;



    /**
     * Добавить таймер
     *
     * @param tt               таймер
     * @param timeoutInSeconds периодичность запуска в секундах
     */
    private void addTimer(TimerTask tt, int timeoutInSeconds) {
        Timer t = new Timer();
        t.scheduleAtFixedRate(tt, 1000, 1000 * timeoutInSeconds);
        timers.add(t);
    }

    /**
     * Запустить таймер на проверку персональных цен
     */
    private void startPersonalPricesExpirationTask(Goodfil gf) {
        if (!SERVICE_PERSONAL_PRICES_EXPIRATION) {
            return;
        }

        //  Проверка персональных цен
        int timeout = gf.getIntOrCreateIfNotExists(PERSONAL_PRICE_EXPIRATION_TIMEOUT_KEY,
                                                   PERSONAL_PRICE_EXPIRATION_TIMEOUT_DEFAULT,
                                                   "Частота вызода проверки персональных цен");
        addTimer(new PersonalPricesExpirationTask(), timeout);
    }

    /**
     * Запустить таймер на проверку окружения
     *
     * @param gf
     */
    private void startEnviromentValidationTask(Goodfil gf) {
        if (!SERVICE_ENVIROMENT_VALIDATION) {
            return;
        }

        //  Проверка окружения
        int timeout = gf.getIntOrCreateIfNotExists(ENVIROMENT_VALIDATION_TIMEOUT_KEY,
                                                   ENVIROMENT_VALIDATION_TIMEOUT_DEFAULT,
                                                   "Частота вызова проверки окружения");
        addTimer(new EnviromentValidationTask(lastMailerValidationResult,
                                              lastBackuperValidationResult,
                                              lastC1IntegrationValidationResult), timeout);
    }

    private final BooleanReference lastC1ValidationResult = new BooleanReference(false);

    private final BooleanReference lastMailerValidationResult = new BooleanReference(false);

    private final BooleanReference lastBackuperValidationResult = new BooleanReference(false);

    private final BooleanReference lastC1IntegrationValidationResult = new BooleanReference(false);

    private void startC1ValidationTask() {
        addTimer(new C1ValidationTask(lastC1ValidationResult), 1000 * 60 * 5);
    }

    /**
     * Запустить таймер на проверку остатков
     */
    private void startRestErrorsTask(Goodfil gf) {
        if (!SERVICE_RESTS_VALIDATION) {
            return;
        }

        //  Проверка нехватки товара для обеспечения заказов
        int timeout = gf.getIntOrCreateIfNotExists(RESTS_VALIDATION_TIMEOUT_KEY,
                                                   RESTS_VALIDATION_TIMEOUT_DEFAULT,
                                                   "Частота вызова проверки остатков");
        addTimer(new RestErrorsTask(), timeout);
    }

    /**
     * Запустить таймер на тестову.ю рассылку остатков
     */
    private void sendTestRests(Goodfil gf) {
        if (!SERVICE_SEND_TEST_RESTS) {
            return;
        }

        //  1, если требуется провести тестовую рассылку остатков
        int sendRests = gf.getIntOrCreateIfNotExists(SEND_RESTS_TEST, SEND_RESTS_TEST_DEFAULT, SEND_RESTS_TEST_COMMENT);

        //  Идентификатор клиента, котому будут отправлены тестовые остатки
        int testClientId = gf.getIntOrCreateIfNotExists(SEND_RESTS_TEST_EMAIL, SEND_RESTS_TEST_EMAIL_VALUE, SEND_RESTS_TEST_EMAIL_COMMENT);

        if (sendRests != 0 && testClientId > 0) {
            logger.warn("Sending test rests...");
            try {
                RestsExportManager.send(gf, testClientId);
                logger.warn("Test rests sent ok");
            } catch (Exception e) {
                logger.error("Test rests sent with error: " + e.getMessage(), e);
            }
        }
    }

    /**
     * Запустить таймер на рассылку остатков
     */
    private void startSchedulerRefreshTask(ServletContextEvent servletContextEvent) {
        String spath = String.valueOf(servletContextEvent.getServletContext().getContextPath()) + String.valueOf(servletContextEvent.getServletContext().getRealPath("/"));

        if (spath.indexOf("Zip1001") != -1) {
            logger.warn("ZIP1001 CRON SETUP");
            addTimer(new SchedulerRefreshTask(), 60 * 60);
        } else {
            logger.warn("zip100? no cron");
        }
    }

    /**
     * Запустить секундомер
     */
    private void startShedulerCountdown() {
        addTimer(new CountDownTask(), 1);
    }

    /**
     * Запуск приложения
     */
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("Goodwill Application initialization");
        configureLogging(servletContextEvent);

        Goodfil gf = GoodfilFactory.getInstance();

        //  Проверка персональных цен
        startPersonalPricesExpirationTask(gf);

        //  Проверка окружения
        startEnviromentValidationTask(gf);

        //  Проверка нехватки товара для обеспечения заказов
        startRestErrorsTask(gf);

        //  Каждый час обновлять насстройки планировщика
        startSchedulerRefreshTask(servletContextEvent);

        //  Проверка взаимодействия с 1С со стороны 1С
        startC1ValidationTask();

        //  Тестовая рассылка остатков
        sendTestRests(gf);

        // Секундомер для блокировок менеджеров
        startShedulerCountdown();
    }

    /**
     * Остановка приложения
     */
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("Goodwill Application unloaded");

        if (timers != null) {
            for (Timer t : timers) {
                releaseTimer(t);
            }
        }
    }

    private void releaseTimer(Timer t) {
        if (t != null) {
            try {
                t.cancel();
            } catch (Exception e) {
            }
        }
    }

    private void configureLogging(ServletContextEvent event) {
        try {
            String home = event.getServletContext().getRealPath("/");
            PropertyConfigurator.configure(home + "WEB-INF/log4j.properties");
            Logger.getLogger(ApplicationInit.class).debug("Logging ok");
        } catch (Exception e) {
            System.out.println("Logging failed");
            e.printStackTrace();
        }
    }
}
